package com.ljh.cloudmusic.service;
import com.ljh.cloudmusic.mapper.LoveMusicMapper;
import com.ljh.cloudmusic.mapper.MusicMapper;
import com.ljh.cloudmusic.mapper.UserMapper;
import com.ljh.cloudmusic.model.Music;
import com.ljh.cloudmusic.model.MusicWithFavorite;
import com.ljh.cloudmusic.model.User;
import com.ljh.cloudmusic.utils.Constant;
import com.ljh.cloudmusic.utils.JwtUtils;
import com.ljh.cloudmusic.utils.ResponseBodyMessage;
import jakarta.servlet.http.HttpServletRequest;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.datatype.Artwork;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;


/**
 * @author: Themberfue
 * @date: 2025/3/9 9:11
 * @description:
 */
@Service
@Transactional
public class MusicService {
    @Value("${music.local.path}")
    private String SAVE_PATH;

    @Autowired
    MusicMapper musicMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    LoveMusicMapper loveMusicMapper;

    public ResponseBodyMessage<Boolean> uploadMusic(@RequestParam("files") List<MultipartFile> files, HttpServletRequest request) throws IOException {
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            return new ResponseBodyMessage<>(-1, "未登录，请登录", null);
        }

        token = token.substring(7);
        User user = userMapper.selectLoginByUsername(JwtUtils.getUsernameFromToken(token));
        if (user == null) {
            return new ResponseBodyMessage<>(-1, "用户不存在", null);
        }

        if (files == null || files.isEmpty()) {
            return new ResponseBodyMessage<>(-1, "上传失败：未收到文件", false);
        }

        Set<String> existingMusic = musicMapper.selectAllTitlesAndArtists(); // 避免重复查询数据库

        for (MultipartFile file : files) {
            String mimeType = file.getContentType();
            if (!Constant.ALLOWED_MIME_TYPES.contains(mimeType)) {
                continue;
            }

            String originalFilename = file.getOriginalFilename();
            String fileExtension = originalFilename != null && originalFilename.contains(".") ?
                    originalFilename.substring(originalFilename.lastIndexOf(".")) : "";

            // 修正 `File.createTempFile` 的问题
            Path tempDir = Paths.get(System.getProperty("java.io.tmpdir")); // 动态获取临时目录
            if (!Files.exists(tempDir)) {
                Files.createDirectories(tempDir);
            }

            File tempFile = Files.createTempFile(tempDir, "music", fileExtension).toFile();
            System.out.println("创建临时文件：" + tempFile.getAbsolutePath());

            try {
                file.transferTo(tempFile);
                if (!tempFile.exists()) {
                    throw new IOException("文件传输失败，临时文件不存在：" + tempFile.getAbsolutePath());
                }

                AudioFile audioFile = AudioFileIO.read(tempFile);
                Tag tag = audioFile.getTag();

                String title = tag.getFirst(FieldKey.TITLE);
                String artist = tag.getFirst(FieldKey.ARTIST);
                String album = tag.getFirst(FieldKey.ALBUM);
                int duration = audioFile.getAudioHeader().getTrackLength();
                double size = tempFile.length() / (1024.0 * 1024.0);

                if (title == null || title.trim().isEmpty() || artist == null || artist.trim().isEmpty()) {
                    System.out.println("跳过：缺少标题或艺术家信息");
                    continue;
                }

                String musicKey = title + "-" + artist;
                if (existingMusic.contains(musicKey)) {
                    System.out.println("跳过：歌曲已存在 " + musicKey);
                    continue;
                }

                int uniqueId = Math.abs(UUID.randomUUID().toString().hashCode());
                while (musicMapper.selectMusicByUUID(uniqueId) != null) {
                    uniqueId = Math.abs(UUID.randomUUID().toString().hashCode());
                }

                String coverPath = SAVE_PATH + uniqueId + ".jpg";
                String coverUrl = "0";
                try {
                    if (tag != null) {
                        System.out.println("读取到音乐 Tag：" + tag.toString());

                        Artwork artwork = tag.getFirstArtwork();
                        if (artwork != null) {
                            byte[] imageData = artwork.getBinaryData();
                            if (imageData != null && imageData.length > 0) {
                                // 确保目录存在
                                Path saveDir = Paths.get(SAVE_PATH);
                                if (!Files.exists(saveDir)) {
                                    Files.createDirectories(saveDir);
                                }

                                // 写入封面文件
                                Files.write(Paths.get(coverPath), imageData);
                                coverUrl = "/music/getCover?path=" + uniqueId + ".jpg";

                                System.out.println("封面文件保存成功：" + coverPath);
                            } else {
                                System.out.println("封面数据为空，使用默认值");
                            }
                        } else {
                            System.out.println("没有读取到封面信息，使用默认值");
                        }
                    } else {
                        System.out.println("音乐文件没有 Tag 信息，无法读取封面");
                    }
                } catch (Exception e) {
                    System.err.println("提取封面时发生异常：" + e.getMessage());
                    e.printStackTrace();
                }


                // 确保目标文件夹存在
                Path saveDir = Paths.get(SAVE_PATH);
                if (!Files.exists(saveDir)) {
                    Files.createDirectories(saveDir);
                }

                // 移动文件
                String newFilePath = SAVE_PATH + uniqueId + fileExtension;
                Files.move(tempFile.toPath(), Paths.get(newFilePath), StandardCopyOption.REPLACE_EXISTING);
                System.out.println("文件移动成功：" + newFilePath);

                Music music = Music.builder()
                        .uuid(uniqueId)
                        .title(title)
                        .artist(artist)
                        .album(album)
                        .duration(duration)
                        .size(size)
                        .coverUrl(coverUrl)
                        .musicUrl("/music/getMusic?path=" + uniqueId + fileExtension)
                        .uploadTime(new SimpleDateFormat("yyyy-MM-dd").format(new Date()))
                        .userId((long) user.getId())
                        .build();

                musicMapper.insertMusic(music);
                existingMusic.add(musicKey);
            } catch (Exception e) {
                System.err.println("处理音乐文件时发生异常：" + e.getMessage());
                e.printStackTrace();
            } finally {
                if (tempFile.exists() && !tempFile.delete()) {
                    System.err.println("无法删除临时文件：" + tempFile.getAbsolutePath());
                }
            }
        }
        return new ResponseBodyMessage<>(0, "批量歌曲上传完成", true);
    }

    public ResponseEntity<Resource> getMusic(String path, HttpServletRequest request) throws IOException {
        path = URLDecoder.decode(path, StandardCharsets.UTF_8);
        System.out.println(path);
        Path filePath = Paths.get(SAVE_PATH, path);
        if (!Files.exists(filePath)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }

        Resource resource;
        try {
            resource = new UrlResource(filePath.toUri());
        } catch (MalformedURLException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }

        long fileLength = Files.size(filePath);
        String rangeHeader = request.getHeader(HttpHeaders.RANGE);

        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.ACCEPT_RANGES, "bytes");

        String contentType = getContentType(path);
        headers.set(HttpHeaders.CONTENT_TYPE, contentType);

        if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
            String[] ranges = rangeHeader.substring(6).split("-");
            long start = Long.parseLong(ranges[0]);
            long end = (ranges.length > 1 && !ranges[1].isEmpty()) ? Long.parseLong(ranges[1]) : fileLength - 1;

            if (start >= fileLength) {
                headers.set(HttpHeaders.CONTENT_RANGE, "bytes */" + fileLength);
                return ResponseEntity.status(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE).headers(headers).build();
            }

            long contentLength = end - start + 1;
            headers.set(HttpHeaders.CONTENT_RANGE, "bytes " + start + "-" + end + "/" + fileLength);
            headers.setContentLength(contentLength);

            return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT).headers(headers).body(resource);
        }

        headers.setContentLength(fileLength);
        return ResponseEntity.ok().headers(headers).body(resource);
    }
    private String getContentType(String filename) {
        String extension = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
        return switch (extension) {
            case "mp3" -> "audio/mpeg";
            case "wav" -> "audio/wav";
            case "flac" -> "audio/flac";
            case "ogg" -> "audio/ogg";
            case "aac" -> "audio/aac";
            case "m4a" -> "audio/mp4";
            default -> "application/octet-stream"; // 未知格式
        };
    }

    public ResponseEntity<Resource> getCover(String path) {
        try {
            File coverFile = new File(SAVE_PATH + path);
            System.out.println(coverFile.getPath());
            if (!coverFile.exists()) {
                return ResponseEntity.badRequest().build();
            }

            // TODO 读取图片并返回
            Resource fileResource = new UrlResource(coverFile.toURI());
            return ResponseEntity.ok()
                    .contentType(MediaType.IMAGE_JPEG) // 或者 IMAGE_PNG
                    .body(fileResource);
        } catch (MalformedURLException e) {
            return ResponseEntity.badRequest().build();
        }
    }

    public ResponseBodyMessage<List<MusicWithFavorite>> getMusicList(HttpServletRequest request) {
        // TODO 获取 Authorization 头部
        String token = request.getHeader("Authorization");

        // TODO 检查 Token 是否有效
        if (token == null || !token.startsWith("Bearer ")) {
            return new ResponseBodyMessage<>(-1, "获取音乐列表失败，请登录后重试", null);
        }

        token = token.substring(7); // 去掉 "Bearer "
        String username = JwtUtils.getUsernameFromToken(token);

        if (username == null) {
            return new ResponseBodyMessage<>(-1, "Token 无效或已过期，请重新登录", null);
        }

        // TODO 查询用户信息
        User user = userMapper.selectLoginByUsername(username);
        if (user == null) {
            return new ResponseBodyMessage<>(-1, "用户不存在，请重新登录", null);
        }

        // TODO 返回音乐列表
        return new ResponseBodyMessage<>(0, "获取音乐列表成功", musicMapper.selectAllMusic(user.getId()));
    }

    public ResponseBodyMessage<Boolean> deleteMusic(List<Integer> ids) {
        List<Music> musics = musicMapper.selectMusicById(ids);
        try {
            for (Music music: musics) {
                // TODO 删除数据库中的该音乐
                Integer id = Integer.parseInt(String.valueOf(music.getId()));
                Integer res = musicMapper.deleteMusicById(id);
                if (res != 0) {
                    // TODO 删除服务器中的该音乐
                    String musicUrl = music.getMusicUrl();
                    String musicFileName = SAVE_PATH + musicUrl.substring(musicUrl.lastIndexOf("=") + 1);
                    File musicFile = new File(musicFileName);
                    // TODO 删除服务器中的该音乐的封面
                    String coverUrl = music.getCoverUrl();
                    if (coverUrl == null) coverUrl = " "; // 歌曲封面不存在
                    String coverFileName = SAVE_PATH + coverUrl.substring(coverUrl.lastIndexOf("=") + 1);
                    File coverFile = new File(coverFileName);
                    musicFile.delete(); coverFile.delete();
                    // TODO 删除 lovemusic 里的该音乐数据
                    loveMusicMapper.deleteLoveMusic(id);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseBodyMessage<>(-1, "删除音乐失败", false);
        }
        return new ResponseBodyMessage<>(0, "删除音乐成功", true);
    }

    public ResponseBodyMessage<List<MusicWithFavorite>> searchMusic(String musicName, HttpServletRequest request) {
        // TODO 获取 Authorization 头部
        String token = request.getHeader("Authorization");

        // TODO 检查 Token 是否有效
        if (token == null || !token.startsWith("Bearer ")) {
            return new ResponseBodyMessage<>(-1, "搜索音乐失败，请登录后重试", null);
        }
        // TODO 去掉 "Bearer " 部分
        token = token.substring(7);
        // TODO 去除多余空格
        musicName = musicName.trim();

        List<MusicWithFavorite> musics;

        // TODO 从 Token 解析出 username，从数据库查询 user
        User user = userMapper.selectLoginByUsername(JwtUtils.getUsernameFromToken(token));

        // TODO 从数据库中查询音乐
        musics = musicMapper.selectMusicByName(user.getId(), musicName);
        return new ResponseBodyMessage<>(0, "查询音乐成功", musics);
    }
}
